#include "OpenglWindow.h"

OpenglWindow::OpenglWindow(LRESULT  (* func) (HWND , UINT ,WPARAM , LPARAM ))
{
	init("OpenGL Window", DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, func);
}

OpenglWindow::OpenglWindow(char *title, LRESULT (* func) (HWND , UINT ,WPARAM , LPARAM ))
{
	init(title, DEFAULT_WINDOW_WIDTH, DEFAULT_WINDOW_HEIGHT, func );
}

OpenglWindow::OpenglWindow(char *title, int w, int h, LRESULT (* func) (HWND , UINT ,WPARAM , LPARAM ))
{
	init(title, w, h, func);
}

OpenglWindow::~OpenglWindow()
{
	this->destroy();
}

/*

FUNCTIONS

*/

void OpenglWindow::init(char *title, int w, int h, LRESULT (* callback) (HWND , UINT ,WPARAM , LPARAM ) )
{
	// Store vars
	this->ready = false;
	this->width = w;
	this->height = h;

	GLuint		pixelFormat;
	WNDCLASS	wc;
	RECT		rect;
	DWORD		dwStyle, dwExStyle;

	rect.left = (long)0;
	rect.right = (long)w;
	rect.top = (long)0;
	rect.bottom = (long)h;

	hInstance		= GetModuleHandle(NULL);
	
	wc.style		= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc	= (WNDPROC) callback;
	wc.cbClsExtra	= 0;
	wc.cbWndExtra	= 0;
	wc.hInstance	= hInstance;
	wc.hIcon		= LoadIcon(NULL, IDI_WINLOGO);		// todo: add logo
	wc.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground= NULL;
	wc.lpszMenuName	= NULL;
	wc.lpszClassName=TEXT("OpenglWindow");

	if (!RegisterClass(&wc))
		throw OpenglWindowException("Failed to register the windows class.");
	

	dwStyle = WS_OVERLAPPEDWINDOW;
	dwExStyle =	WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;

	AdjustWindowRectEx(&rect, dwStyle, false, dwExStyle);


	hWnd = CreateWindowEx(	dwExStyle,
					TEXT("OpenglWindow"),
					TEXT("Tetris"),
					WS_CLIPSIBLINGS |
					WS_CLIPCHILDREN |
					dwStyle,
					0, 0,
					rect.right-rect.left,
					rect.bottom-rect.top,
					NULL,
					NULL,
					hInstance,
					NULL);


	if (!hWnd) 
		throw OpenglWindowException("Failed to create hWnd.");
	

	static PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),
			1,
			PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA,
			32, // 32bits
			0, 0, 0, 0, 0, 0,	 // color bits
			0,					// alpha buffer
			0,
			0,
			0,
			0, 0, 0, 0,
			16,		// depth
			0,
			0,
			PFD_MAIN_PLANE,
			0,
			0, 0, 0
	};

	hDC = GetDC(hWnd);
	if (!hDC)
		throw OpenglWindowException("Failed to create the hDC.");

	pixelFormat = ChoosePixelFormat(hDC, &pfd);
	if (!pixelFormat)
		throw OpenglWindowException("Failed to create a pixel format.");

	if (!SetPixelFormat(hDC, pixelFormat, &pfd))
		throw OpenglWindowException("Failed to set the pixel format.");

	hRC = wglCreateContext(hDC);
	if (!hRC)
		throw OpenglWindowException("Failed to create the rendering context.");

	if (!wglMakeCurrent(hDC, hRC))
		throw OpenglWindowException("Failed to activate the rendering context.");



	if (!this->initGL())
		throw OpenglWindowException("Failed to initalize OpenGL.");

	this->ready = true;
}
bool OpenglWindow::initGL()
{
	glEnable(GL_TEXTURE_2D);
	glShadeModel(GL_SMOOTH);
	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LEQUAL);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	return true;
}


void OpenglWindow::show()
{
	if (!this->ready)
		throw OpenglWindowException("Failed to show the window: The window has not been initialized yet.");

	ShowWindow(hWnd, SW_SHOW);
	SetForegroundWindow(hWnd);
	SetFocus(hWnd);
	this->resize(this->width, this->height);
}

void OpenglWindow::resize(int w, int h)
{
	if (h==0) h = 1;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(45.0f, (GLfloat)w/(GLfloat)h, 0.1f, 200.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	//this->swapBuffers();
	
}

void OpenglWindow::swapBuffers()
{
	SwapBuffers(hDC);
}	
void OpenglWindow::destroy()
{
	if (hRC)
	{
		wglMakeCurrent(NULL, NULL);
		wglDeleteContext(hRC);
		hRC = NULL;
	}
	if (hDC)
		ReleaseDC(hWnd, hDC);

	if (hWnd)
		DestroyWindow(hWnd);

	UnregisterClass(TEXT("OpenglWindow"), hInstance);
}
